package com.cwnu.sw.cys.core.common.utils;

import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
/**
 * @author jisam
 * @version 1.0
 * @contact "jisamchan@outlook.com"
 * @date 25/03/2025
 * @description springEl 表达式 工具类
 */
public class SpElUtils {
    /**
     * 静态常量，用于解析Spring表达式语言（SpEL）的表达式。
     * 该解析器是线程安全的，可以在整个应用程序中共享使用。
     */
    private static final ExpressionParser PARSER = new SpelExpressionParser();

    /**
     * 静态常量，用于发现方法参数的名称。
     * 该发现器通过反射机制获取方法参数的名称，通常用于解析方法参数名以支持表达式中的参数引用。
     */
    private static final DefaultParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();

    /**
     * 解析Spring EL表达式并返回结果
     *
     * @param method 目标方法，用于获取参数名称
     * @param args 目标方法的参数值，用于填充EL表达式中的变量
     * @param spEl 需要解析的Spring EL表达式
     * @return 解析后的字符串结果
     */
    public static String parseSpEl(Method method, Object[] args, String spEl) {
        // 获取方法的参数名称，如果无法获取则返回空数组
        String[] params = Optional.ofNullable(PARAMETER_NAME_DISCOVERER.getParameterNames(method)).orElse(new String[]{});

        // 创建EL表达式解析的上下文对象
        EvaluationContext context = new StandardEvaluationContext();

        // 将方法的参数名称和对应的值设置到上下文中
        for (int i = 0; i < params.length; i++) {
            context.setVariable(params[i], args[i]);
        }

        // 解析并执行EL表达式，返回字符串结果
        Expression expression = PARSER.parseExpression(spEl);
        return expression.getValue(context, String.class);
    }

    /**
     * 生成方法的唯一标识符，格式为 "类名#方法名"
     *
     * @param method 目标方法
     * @return 方法的唯一标识符
     */
    public static String getMethodKey(Method method) {
        return method.getDeclaringClass() + "#" + method.getName();
    }


    /**
     * 主函数，用于演示如何使用Spring Expression Language (SpEL) 解析和获取列表数据。
     *
     * 该函数主要执行以下步骤：
     * 1. 创建一个包含整数的列表。
     * 2. 使用SpEL解析表达式并获取列表数据。
     * 3. 打印解析后的结果。
     *
     * @param args 命令行参数，本函数中未使用。
     */
    public static void main(String[] args) {
        // 创建一个包含1到10的整数列表
        List<Integer> arr = new ArrayList<>();
        arr.addAll(Arrays.asList(1,2,3,4,5,6,7,8,9,10));

        // 创建SpEL的上下文对象，并将列表设置为上下文中的变量
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariable("arr", arr);

        // 使用SpEL解析表达式 "#arr"，该表达式表示获取上下文中的 "arr" 变量
        Expression expression = PARSER.parseExpression("#arr");

        // 从上下文中获取解析后的列表数据，并强制转换为List<Integer>类型
        List<Integer> result = (List<Integer>) expression.getValue(context, List.class);

        // 打印解析后的列表数据
        System.out.println(result);
    }
}
